package com.llbnk.springcoding.service;


import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.llbnk.springcoding.annotation.RedLock;
import com.llbnk.springcoding.config.TestExcutor;
import com.sun.istack.internal.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class BlockService {

    private static final ThreadPoolExecutor BLOCK_EXECUTOR = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(1),new ThreadFactoryBuilder().setNameFormat("block-service-%d").build(),
            new ThreadPoolExecutor.DiscardPolicy());


    private static final int INIT_NUMBER = 10;

    @Autowired
    private TestExcutor testExcutor;


    /**
     * 用于测试异步方法堵塞问题
     */
    public void testAsyncBlock() {
        long startTime = System.currentTimeMillis();
        ArrayList<Long> fillLists = new ArrayList<>();
        for (long i=1;i<10;i++){
            fillLists.add(i);
        }
        CompletableFuture.allOf(fillLists.stream().map(t -> CompletableFuture.supplyAsync(()->{
            System.out.println(t);
            return "ok";
        },BLOCK_EXECUTOR)).toArray(CompletableFuture[]::new)).join();
        log.info("[testAsyncBlock] cost time:{}",System.currentTimeMillis()-startTime);
    }


    public List<Integer> testAsyncFuture(List<Integer> numbers) {
        //1.准备默认返回list
        ArrayList<Integer> result = new ArrayList<>();
        //2.获取需要填充信息
        List<Integer> fillList = fillListNumber(numbers);
        //3.填充list
        result.addAll(fillList);

        return result;
    }

    private List<Integer> fillListNumber(List<Integer> numbers) {
        List<CompletableFuture<Integer>> futures = getCompletableFuturesByNumbers(numbers);
        List<Integer> totalNums = new ArrayList<>(numbers.size());
        for (int i = 0; i < numbers.size(); i++) {
            try {
                CompletableFuture<Integer> future = futures.get(i);
                Integer totalNum = future.get(50,TimeUnit.MILLISECONDS);
                totalNums.add(totalNum);
            } catch (InterruptedException | ExecutionException | TimeoutException e) {
                totalNums.add(INIT_NUMBER);
            }
        }
        return totalNums;
    }

    @NotNull
    private List<CompletableFuture<Integer>> getCompletableFuturesByNumbers(List<Integer> numbers) {
        List<CompletableFuture<Integer>> futures =  numbers.stream().filter(Objects::nonNull)
                .map(transporterId -> CompletableFuture.supplyAsync(() -> {
                    try {
                        try {
                            //复杂处理逻辑
                            return INIT_NUMBER;
                        } catch (Exception e) {
                            log.info("[getCompletableFuturesByNumbers]",e);
                        }
                    } finally {
                    }
                    return INIT_NUMBER;
                }, testExcutor.getTaskExecutor())).collect(Collectors.toList());
        return futures;
    }



    @RedLock(key = "'spring-coding:'+#userId",leaseTime = 1,waitTime = 1)
    public String testAnnotationRedLock(Integer userId) {
        //在分布式锁中，处理业务
        log.info("in redlock process,userId:{}",userId);
        //模拟处理时间
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "ok";
    }
}
